#pragma once
#ifndef DIS_PSET
#define DIS_PSET
#include "FileMapping.hpp"
#include "thread_manager.hpp"

//判断x字符是否可能为数字的一部分
#define might_be_num(x) ((x>='0'&&x<='9')||(x=='.')||(x=='-'))

//dis_point: 用于存储赛题二中点以及对应应力分量值
//定义为结构体，方便后续直接操作
typedef struct dis_point {
    dis_point() {
        x = 0.0;
        y = 0.0;
        z = 0.0;
        val = 0.0;
    }
    dis_point(double a,double b,double c) {
        x = a;
        y = b;
        z = c;
        val = 0.0;
    }
    double x, y, z, val;
}dis_point;

//dis_pset: 点集，用于处理赛题二中离散点网格
class dis_pset {
public:
    char* file_ptr = nullptr;   //文件内容指针
    long long file_len = 0;     //文件长度

    dis_point* data = nullptr;  //实际点指针
    int size = 0;               //点集大小

    thread_manager thm;         //多线程管理
    int thread_num = 0;         //线程数

    //构造函数
    //filename: 文件名
    //type: 输入文件类型，type==0为原始网格，type==1为目标网格
    //thnum: 线程数
    dis_pset(const char* filename, int type,int thnum = 0) {
        //获取线程数
        thread_num = thnum;

        //将文件映射至内存
        FileMapping obj(filename, 1);
        //获取文件内容指针、文件长度
        file_ptr = obj.read_content();
        file_len = obj.len_of_reading_file();

        //调用初始化函数
        init(type,thread_num);

        //关闭文件映射
        file_ptr = nullptr;
        file_len = 0;
        obj.close();
    }

    //原始网格初始化函数
    //type: 输入文件类型，type==0为原始网格，type==1为目标网格
    //thread_num 线程数
    void init(int type,int thread_num = 0){
        int* valid = new int[thread_num + 1];  //用于记录各线程读取有效值
        for (int i = 0; i < thread_num + 1; i++)
            valid[i] = 0;

        if (thread_num != 0) {
            //多线程初始化
            thm.thread_init(thread_num);
            //多线程任务分发
            thm.run_thread(&dis_pset::read, this,type, file_ptr, file_len, valid);
        }
        //主线程运行
        read(type,file_ptr,file_len, valid);
        //等待子线程结束
        thm.join();
    }


    //要求文件输出函数
    //outfile 输出文件名
    void output(const char* outfile) {
        int* len = new int[thread_num + 1];  //记录个线程输出内容长度
        for (int i = 0; i < thread_num + 1; i++)
            len[i] = 0;

        //将文件映射到内存
        FileMapping obj(outfile,0);
        string *data=new string[thread_num + 1];  //记录各线程输出内容
        int thread_wrting = 0;
        if (thread_num != 0) {
            //多线程初始化
            thm.thread_init(thread_num);
            //多线程任务分发
            thm.run_thread(&dis_pset::write, this, &obj, data);
        }
        //主线程运行
        write(&obj, data);
        thm.join();

        //关闭文件映射
        obj.close();
        cout<<"Writing property:"<<outfile<<'\n';
    }

    //根据传入的num类型，从file_content中获取一个数字，同时变更表明位置的ptr
    //仅支持int和double
    template<class type>
    type get_a_num(const char*file_content,long long &ptr,type num) {
        type res = num;
        //跳过非数字相关字符
        while (file_content[ptr]!='\0'&&!might_be_num(file_content[ptr]))
        {
            ++ptr;
        }
        //获取数字
        if (typeid(num)==typeid(int)) {
            res = atoi(file_content + ptr);
        }
        else if (typeid(num) == typeid(double)) {
            res = atof(file_content + ptr);
        }
        //跳过读入的数字
        while (might_be_num(file_content[ptr]))
        {
            ++ptr;
        }
        //返回
        return res;
    }

private:
    //原始网格读取函数
    //content: 文件内容指针
    //file_len: 文件长度
    //valid: 记录有效数据数量
    //tid: 线程编号
    void read(int type,const char* content, long long file_len, int* valid, int tid = 0);

    
    void write(FileMapping *obj, string* str, int tid = 0);
};

#endif